//============================================================================
// Name        : student-management-system
// Author      : fanfangqiang
// Version     : 1.00
// Copyright   :
// Description : my first project
//功能实现:2020/11/3,实行了大部分功能,有一个缺陷,在实现修改学生信息时,在录入新的信息之后,不能删除原有的信息
//修改学生记录出有bug,应该是链表的链接有问题了
//============================================================================

#include <stdio.h>
#include<string.h>
#include<malloc.h>
#include<stdlib.h>
#include<stdbool.h>

#define NO_LENGTH  20
#define NAME_LENGTH 11

/* 定义学生结构体的数据结构 */
typedef struct Student{
    char studentNo[NO_LENGTH];
    char studentName[NAME_LENGTH];
}st;

/* 定义每条记录或节点的数据结构 */
typedef struct node
{
    struct Student data; //数据域
    struct node *next; //指针域
}Node,*Link;  //Node为node类型的别名,Link为node类型的指针别名

//定义提示菜单
void myMenu(){
    printf(" * * * * * * * * * 菜     单 * * * * * * * * * *\n");
    printf("     1 增加学生记录            2 删除学生记录                     \n");
    printf("     3 查找学生记录            4 修改学生记录                     \n");
    printf("     5 统计学生人数            6 显示学生记录                     \n");
    printf("     7 退出系统                                     \n");
    printf(" * * * * * * * * * * * * * * * * * * * * * * * *\n");
}
int delete_list(Link head,char no[]);
bool insert_list(Link head,Link node);
void inputStudent(Link l){
     printf("请输入学生学号:");
     scanf("%s",l->data.studentNo);
     printf("请输入学生的姓名:");
     scanf("%s",l->data.studentName);

     //每个新创建的节点的next域都初始化为NULL
     l->next = NULL;
}

void inputStudentNo(char s[],char no[]){
    printf("请输入要%s的学生学号:",s);
    scanf("%s",no);
}

void displayNode(Link head){
    if (head == NULL || head->next == NULL)
    {
        printf ("没有学生信息,请录入\n");
        return;
    }
    Link p = head->next;
    while (p != NULL)
    {
        printf ("学生学号:%s    学生姓名:%s\n",p->data.studentNo,p->data.studentName);
        p = p->next;
    }
   // 填写代码，根据传入的链表head头指针，扫描链表显示所有节点的信息
}

/* 增加学生记录
 为保证.学生记录的有序性,故在插入时就进行有序的插入
有三种情况:
1.增加的节点是该系统的第一个学生信息
2.增加的节点是中间节点
3.增加的节点是最后一个节点
*/
bool addNode(Link head)
{
   //定义node,p,q节点;
    Link node,p,q;
    node = (Link)malloc(sizeof(Node));
    inputStudent(node);
    if (head == NULL)
        return false;
    //增加学生记录为首个
    else if (head->next == NULL){
        head->next = node;
        return true;
    }
    //增加学生记录为中间
    else
    {
        p = head;
        q = head->next;

        while (q != NULL)
        {
              //如果node节点在q前面
                if (strcmp(node->data.studentNo,q->data.studentNo) < 0)
                {
                    node->next = p->next;
                    p->next = node;
                    return true;
                }
                //如果node节点在q后面,则将p,q向后移动
                else
                {
                    p = q;
                    q = q->next;
                }
        }
        //如果退出循环了,就说明node节点是最后一个节点
        p->next = node;

    }
    return true;
}


bool deleteNode(Link head){

    // 按照给定的学号删除学生记录，如果删除成功返回true，如果没找到学号返回false
    //首先要确保head不为空表
    if(head == NULL || head->next == NULL){
        printf ("链表为空\n");
            return false;}
    //输入要处理的学号
    char no[NO_LENGTH];
    inputStudentNo("删除",no);
    //printf ("%s",no);

    //使用pq两个指针,并保证其一前一后
    Link p,q;
     p = head;
     q = head->next;

     while (q != NULL)
     {
         if (strcmp(q->data.studentNo,no) == 0)
         {
             p->next = q->next;
             free(q);
             return true;
         }
         else
         {
             p = q;
             q = q->next;
         }
     }
    return false;
}

bool queryNode(Link head){
    // 按照给定的学号查询学生记录，如果删除成功返回true，如果没找到学号返回false
    if(head == NULL || head->next == NULL){
        printf ("链表为空\n");
            return false;}

    //输入要处理的学号
    char no[NO_LENGTH];
    inputStudentNo("查询",no);
    Link p;
    p = head->next;
    while (p != NULL)
    {
        if (strcmp(p->data.studentNo,no) == 0)
            return true;
        else
        {
            p = p->next;
        }
    }
    return false;
}

bool modifyNode(Link head){
    // 按照给定的学号找到学生记录节点，如果修改成功返回true，如果没找到学号返回false
    if(head == NULL || head->next == NULL){
        printf ("链表为空\n");
            return false;}
    int num;
    //输入要处理的学号
    Link p = head;
    Link tmp = NULL;
    tmp = (Link)malloc(sizeof(Node));
    char no[NO_LENGTH];
    inputStudentNo("修改",no);
    //printf ("%s\n",no);
    //输入新的学生姓名学号
    printf ("请输入新的姓名:");
    scanf ("%s",tmp->data.studentName);
    printf ("请输入新的学号:");
    scanf ("%s",tmp->data.studentNo);
    /*方法1:失败
    //将新的节点有序插入链表中
    if (insert_list(head,tmp))
        return true;
    else
        return false;
    //找到要修改的节点并删除,如果没找到返回false
    num = delete_list(head,no);
    if (num == -1)
        return false;*/
       //方法2
       while(p != NULL)
       {
           if (strcmp(p->data.studentNo,no) == 0)
           {
               strcpy(p->data.studentNo,tmp->data.studentNo);
               strcpy(p->data.studentName,tmp->data.studentName);
               insert_list( head,p);
               p->next = NULL;
               return true;
           }
           else
               p = p->next;

       }
       return false;




   /* printf ("请输入要修改的内容,学号为1,姓名为2:\n");
    scanf ("%d",&num);
    if (num == 2)
    {
        printf ("请输入修改后的姓名:\n");
        scanf("%s",tmp->data.studentName);
        while (p != NULL)
        {
              if (strcmp(p->data.studentNo,no) == 0)
                  strcpy(p->data.studentName,tmp->data.studentName);
              else
                  p = p->next;
        }
         return true;
    }
    else//对学号修改之后还要对其进行排序

            首先要将名字拷贝到临时节点
            然后将修改的节点删除
            然后重新插入临时节点

    {
        printf ("请输入修改后的学号:\n");
        scanf("%s",tmp->data.studentNo);
        while (p != NULL)
        {
              if (strcmp(p->data.studentNo,no) == 0)
                  strcpy(p->data.studentName,tmp->data.studentName);
              else
                  p = p->next;
        }
        *///对姓名或者学号中的单独一个元素进行修改的话,很复杂,遂放弃
}

 int countNode(Link head){
    //统计学生人数，扫描链表统计节点个数，返回节点数
    Link p;
    int count = 0;
    p = head->next;
    while (p != NULL)
    {
        count ++;
        p = p->next;
    }

    //填充代码
    return count;

}

void clearLink(Link head){
    Link q;
  //遍历链表，用free语句删除链表中用malloc建立起的所有的节点

    while (head != NULL)
    {
         q = head;
        head = head->next;
        free(q);
    }


}


int main(void) {
    int select;
        int count;
    Link head;  // 定义链表


    //建立head头结点，在这个程序中head指向头结点，头结点data部分没有内容，其后续节点才有真正的数据
    head = (Link)malloc(sizeof(Node));
    head->next = NULL;

    while(1)
    {
        myMenu();
        printf("\n请输入你的选择(1-7):");  //显示提示信息
        scanf("%d",&select);

        switch(select)
        {
        case 1:
            //增加学生记录
            if(addNode(head))
                printf("成功插入一个学生记录。\n\n");
            break;
        case 2:
            //删除学生记录
            if(deleteNode(head))
                printf("成功删除一个学生记录。\n\n");
            else
                printf("没有找到要删除的学生节点。\n\n");
            break;
        case 3:
            //查询学生记录
            if(queryNode(head))
                printf("成功找到学生记录。\n\n");
            else
                printf("没有找到要查询的学生节点。\n\n");
            break;
        case 4:
            //修改学生记录
            if(modifyNode(head))
                printf("成功修改一个学生记录。\n\n");
            else
                printf("没有找到要修改的学生节点。\n\n");
            break;
        case 5:
            //统计学生人数
            count = countNode(head);
            printf("学生人数为：%d\n\n",count);
            break;
        case 6:
            //显示学生记录
            displayNode(head);
            break;
        case 7:
            //退出前清除链表中的所有结点
            clearLink(head);
            return 0;
        default:
            printf("输入不正确，应该输入0-7之间的数。\n\n");
            break;
        }
    }
    return 0;
}
int delete_list(Link head,char no[])//找到链表中元素为x的节点,并删除
{
    //首先要确保head不为空表
    if(head == NULL || head->next == NULL)
        return -1;
    //使用pq两个指针,并保证其一前一后
    printf ("%s",no);
    Link p,q;
     p = head;
     q = head->next;

     while (q != NULL)
     {
         if (strcmp(p->data.studentNo,no) == 0)
         {
             p->next = q->next;
             free(q);
             return 1;
         }
         else
         {
             p = q;
             q = q->next;
         }
     }
     //return -1;
}
bool insert_list(Link head,Link node)
{
   //定义node,p,q节点;
    Link p,q;
    //增加学生记录为首个
    if (head->next == NULL){
        head->next = node;
        return true;
    }
    //增加学生记录为中间
    else
    {
        p = head;
        q = head->next;

        while (q != NULL)
        {
              //如果node节点在q前面
                 if (strcmp(node->data.studentNo,q->data.studentNo) < 0)
                {
                    node->next = p->next;
                    p->next = node;
                    return true;
                }
                //如果node节点在q后面,则将p,q向后移动
                else
                {
                    p = q;
                    q = q->next;
                }
        }
        //如果退出循环了,就说明node节点是最后一个节点
        p->next = node;

    }
    return true;
}
